﻿using System;
using Autofac;
using Autofac.Builder;
using Autofac.Features.ResolveAnything;
using Moq;

namespace MoqContrib.AutoMock.Autofac
{
	public class InstanceProvider : IInstanceProvider
	{
		public InstanceProvider()
		{
			// FIXME: we'll want to allow the user to configure behavior somehow.
			// I'll change the behavior as soon as I understand what the user facing
			// API/process looks like.
			var repository = new MockRepository(MockBehavior.Loose);
			var builder = new ContainerBuilder();
			builder.RegisterInstance(repository);
			builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
			builder.RegisterSource(new MoqRegistrationHandler());
			Container = builder.Build();
		}

		protected IContainer Container { get; set; }

		public object GetInstance(Type type)
		{
			return Container.Resolve(type);
		}

		public T GetInstance<T>()
		{
			return Container.Resolve<T>();
		}

		// FIXME ?? should we allow specifying the concrete type distinctly from
		// a possible interface type?
		public void SetInstance(Type type, object instance)
		{
			Container.ComponentRegistry.Register(
				RegistrationBuilder
					.ForDelegate((c, p) => instance).As(type)
					.InstancePerLifetimeScope().CreateRegistration()
				);
		}

		public void SetInstance<T>(T instance)
		{
			Container.ComponentRegistry.Register(
				RegistrationBuilder
					.ForDelegate((c, p) => instance)
					.InstancePerLifetimeScope().CreateRegistration()
				);
		}
	}
}
